github.com/NebulousLabs/Sia@v1.3.7/doc/Running and Writing Tests for Sia.md (about) 1 # Running and Writing Tests for Sia 2 Improving test coverage is a great way to start contributing to Sia. 3 4 This guide focuses on how to write tests. To learn about making pull requests 5 to submit the code you've written, see 6 [doc/Guide to Contributing to Sia.md][guide]. You should also read 7 [doc/Developers.md][developers] to learn about Sia code conventions and quality 8 standards. 9 10 11 #### Table of Contents 12 * [Running tests for Sia](#existing) 13 * [Updating code before testing](#update) 14 * [Testing the entire build](#entire) 15 * [Testing a particular package](#particular) 16 * [Writing new tests for Sia](#write) 17 * [A few guidelines](#naming) 18 * [Basic test format](#basic) 19 * [Table-driven tests](#table) 20 * [Questions?](#questions) 21 22 <a name="existing"></a> 23 ## Running tests for Sia 24 Go's comprehensive [test package][pkg/testing] makes testing straightforward, 25 particularly when you use the bundled tools included in the 26 [Sia makefile][makefile], including `make test`, `make cover`, `make bench`, 27 and their variants. 28 29 <a name="update"></a> 30 ### Updating code before testing 31 If you just want to run existing tests on the codebase as is, you just need to 32 pull the latest version of the original repo to your master branch. (If that 33 sentence didn't make sense, go read 34 [doc/Guide to Contributing to Sia.md][guide].) 35 36 ```bash 37 # Make sure you are in the right directory. 38 $ cd $GOPATH/src/github.com/<your Github username>/Sia 39 # Also make sure you're working with the right branch. 40 $ git checkout master 41 # Pull latest changes from origin, the original Sia repo. 42 $ git pull origin master 43 # Update your fork of the repo, which should be set up as a remote. 44 $ git push <remote> master 45 ``` 46 47 If you want to run tests on the new code you've added, first make sure the rest 48 of the code is up to date. New code should be on its own branch (again, see 49 [doc/Guide to Contributing to Sia.md][guide]). 50 51 ```bash 52 # Make sure you are in the right directory. 53 $ cd $GOPATH/src/github.com/<your Github username>/Sia 54 # Checkout the branch you made the changes on. 55 $ git checkout <branch name> 56 # Stash any tracked but uncommitted changes. 57 $ git stash 58 # Then switch back to `master` and update it to match the original repo. 59 $ git checkout master 60 $ git pull origin master 61 # Update your fork of the repo, which you should have set up as a remote. 62 $ git push <remote> master 63 # Make the updated `master` the new base of the branch you made the changes on, 64 # which involves reapplying all the commits made to that branch. Without the 65 # `--ignore-date` flag, git rebase changes the date on all the commits to the 66 # current date. 67 $ git checkout <branch name> 68 $ git rebase master --ignore-date 69 # Restore the changes you stashed earlier. 70 $ git stash pop 71 ``` 72 When you call `rebase`, you may run into some merge conflicts. Luke Champine's 73 ['How to into git and GitHub'][luke] has more details (and many useful tricks). 74 75 Once the branch you want to test is up to date, you're ready to run some tests. 76 77 <a name="entire"></a> 78 ### Testing the entire build 79 The `make test` command runs all tests (functions starting with `Test` in 80 `_test.go` files) for each package, setting off a panic for any test that runs 81 longer than 5s. For verbose output, run `make test-v` (which panics after 15s 82 instead of 5s). Finally, `make test-long` has verbose output, only panics when 83 a test takes 5 minutes, and also cleans up your code using `gofmt` and `golint`. 84 **You should run** `make test-long` **before each pull request.** 85 86 Run `make cover` to run all tests for each package and generate color-coded 87 .html visualizations of test coverage by function for each source file. Open 88 `cover/<module>.html` in a browser to inspect a module's test coverage. For 89 example, here's part of the html file generated for the persist package: 90 91 ![Screenshot](assets/covertool.png) 92 93 Meanwhile, `make bench` will call `gofmt` on all packages, then run all 94 benchmarks (functions starting with `Benchmark` in `_test.go` files). 95 96 <a name="particular"></a> 97 ### Testing a particular package or function 98 To run tests for just a certain package, run `make test pkgs=./<package>`. To run 99 a certain test function, run `make test pkgs=./<package> run=<function>`. The same 100 goes for `make test-long`, `make cover` and `make bench`. 101 102 For example, running `test-long` on the package persist produces this output: 103 104 ```bash 105 $ make test-long pkgs=./persist 106 rm -rf release doc/whitepaper.aux doc/whitepaper.log doc/whitepaper.pdf 107 gofmt -s -l -w ./persist 108 go install ./persist 109 go vet ./persist 110 go test -v -race -tags='testing debug' -timeout=300s ./persist -run=Test 111 === RUN TestOpenDatabase 112 --- PASS: TestOpenDatabase (0.42s) 113 === RUN TestSaveLoad 114 --- PASS: TestSaveLoad (0.00s) 115 === RUN TestSaveLoadFile 116 --- PASS: TestSaveLoadFile (0.01s) 117 === RUN TestSaveLoadFileSync 118 --- PASS: TestSaveLoadFileSync (0.00s) 119 === RUN TestLogger 120 --- PASS: TestLogger (0.00s) 121 === RUN TestLoggerCritical 122 --- PASS: TestLoggerCritical (0.00s) 123 === RUN TestIntegrationRandomSuffix 124 --- PASS: TestIntegrationRandomSuffix (0.01s) 125 === RUN TestAbsolutePathSafeFile 126 --- PASS: TestAbsolutePathSafeFile (0.00s) 127 === RUN TestRelativePathSafeFile 128 --- PASS: TestRelativePathSafeFile (0.00s) 129 PASS 130 ok github.com/NebulousLabs/Sia/persist 1.485s 131 $ 132 ``` 133 134 <a name="write"></a> 135 ## Writing new tests for Sia 136 When you run `make cover`, you'll notice that many files have pretty low 137 coverage. We're working on fixing that, but we could use your help. 138 139 <a name="naming"></a> 140 ### A few guidelines 141 * The test functions for `filename.go` should go in `filename_test.go` in the 142 same directory and package. 143 * A test function name should start with `Test` and clearly convey what is 144 being tested. 145 * You should declare function-specific variables and constants locally (inside 146 the test function) instead of globally (outside the test function). [That 147 holds in general][global], not just for tests. 148 * As always, code should adhere to the standards and conventions laid out in 149 [doc/Developers.md][developers]. 150 151 <a name="basic"></a> 152 ### Basic test format 153 Suppose we'd like to test the Bar method belonging to type Foo. 154 155 ```go 156 // TestFoo checks that the Bar method on type Foo responds correctly to a normal 157 // input and returns the expected error when given a bad input. 158 func TestFoo(t *testing.T) { 159 foo, err := NewFoo() 160 if err != nil { 161 // If NewFoo failed, we can't continue testing. 162 t.Fatal(err) 163 } 164 165 // Try a normal input; should succeed. 166 err := foo.Bar(3) 167 if err != nil { 168 // Report the error, but don't abort the test. 169 t.Error(err) 170 } 171 172 // Try a bad input; should return an error. 173 // NOTE: Always prefer to compare to a specific error, rather than 174 // err == nil 175 err = Foo.Bar(0) 176 if err != errDivideByZero { 177 t.Errorf("expected errDivideByZero, got %v", err) 178 } 179 } 180 181 ``` 182 183 <a name="table"></a> 184 ### Table-driven tests in Go 185 If you're looking to test a bunch of inputs, write a [table-driven test][table] 186 with a slice of anonymous structs. For example, see `TestParseFileSize` in 187 [siac/parse_test.go][parse_test]: 188 189 ```go 190 func TestParseFilesize(t *testing.T) { 191 // Define a table of test cases in the form of a slice of anonymous structs. 192 tests := []struct { 193 in, out string 194 err error 195 }{ 196 {"1b", "1", nil}, 197 {"1KB", "1000", nil}, 198 {"1MB", "1000000", nil}, 199 {"1GB", "1000000000", nil}, 200 {"1TB", "1000000000000", nil}, 201 {"1KiB", "1024", nil}, 202 {"1MiB", "1048576", nil}, 203 {"1GiB", "1073741824", nil}, 204 {"1TiB", "1099511627776", nil}, 205 {"", "", errUnableToParseSize}, 206 {"123", "123", nil}, 207 {"123TB", "123000000000000", nil}, 208 {"123GiB", "132070244352", nil}, 209 {"123BiB", "", errUnableToParseSize}, 210 {"GB", "", errUnableToParseSize}, 211 {"123G", "", errUnableToParseSize}, 212 {"123B99", "", errUnableToParseSize}, 213 {"12A3456", "", errUnableToParseSize}, 214 {"1.23KB", "1230", nil}, 215 {"1.234KB", "1234", nil}, 216 {"1.2345KB", "1234", nil}, 217 } 218 // Loop through the table of test cases to make sure ParseFileSize returns 219 // the expected output and error for each. 220 for _, test := range tests { 221 res, err := parseFilesize(test.in) 222 if res != test.out || err != test.err { 223 t.Errorf("parseFilesize(%v): expected %v %v, got %v %v", test.in, test.out, test.err, res, err) 224 } 225 } 226 } 227 ``` 228 <a name="questions"></a> 229 ## Questions? 230 Read these if you haven't already: 231 * [doc/Guide to Contributing to Sia.md][guide]: getting started with Go, Sia, 232 and git 233 * [doc/Developers.md][developers]: conventions and quality standards for Sia 234 code 235 236 Some other useful resources, some of which have been linked to already: 237 * [Golang.org page on the go testing package][pkg/testing] 238 * [Writing Table-Driven Tests in Go][table] 239 * [How to Write Benchmarks in Go][cheney-benchmarks] 240 * [How to into git and GitHub][luke]: an essential introduction to git 241 242 And feel free to ask questions on the [#core-dev channel][discord] on the Sia Discord. 243 Odds are, someone else is wondering the same thing. 244 245 [pkg/testing]: https://golang.org/pkg/testing/ 246 [makefile]: https://github.com/NebulousLabs/Sia/blob/master/Makefile 247 [luke]: https://gist.github.com/lukechampine/6418449 248 [guide]: https://github.com/NebulousLabs/Sia/blob/master/doc/Guide%20to%20Contributing%20to%20Sia.md 249 [developers]: https://github.com/NebulousLabs/Sia/blob/master/doc/Developers.md 250 [table]: http://dave.cheney.net/2013/06/09/writing-table-driven-tests-in-go 251 [boltdb_test.go]: https://github.com/NebulousLabs/Sia/blob/master/persist/boltdb_test.go 252 [cheney-benchmarks]: http://dave.cheney.net/2013/06/30/how-to-write-benchmarks-in-go 253 [pkg/testing]: https://golang.org/pkg/testing/ 254 [discord]: https://discord.gg/sia 255 [parse_test]: https://github.com/NebulousLabs/Sia/blob/master/siac/parse_test.go 256 [global]: http://c2.com/cgi/wiki?GlobalVariablesAreBad